package de.koller.aframe.util.misc;

import de.koller.aframe.plain.PlainRasterFloat3D;
import de.koller.oceanFramework.util.MIn;
import de.koller.oceanFramework.util.MOut;
import java.io.File;
import java.util.LinkedList;
import java.util.Random;

public class BufferedRandomFloat3D {

	public static final int MAX_LOADED_CHUNKS = 64;
	public static final int CHUNK_SIZE = 128;
	
	private final Random rnd;
	private final String bufferRoot;
	
	private LinkedList<BufferedRandomFloat3D.FloatChunk3D> chunks = new LinkedList<>();
	
	public BufferedRandomFloat3D( String bufferRoot, Random rnd ) {
		this.rnd = rnd;
		this.bufferRoot = bufferRoot;
	}
	
	public float get( int ax, int ay, int az, int level, int type ) {
		int vx = (int)Math.floor( (float)ax / (float)CHUNK_SIZE ) * CHUNK_SIZE;
		int vy = (int)Math.floor( (float)ay / (float)CHUNK_SIZE ) * CHUNK_SIZE;
		int vz = (int)Math.floor( (float)az / (float)CHUNK_SIZE ) * CHUNK_SIZE;
		int dx = ax - vx;
		int dy = ay - vy;
		int dz = az - vz;
		
		BufferedRandomFloat3D.FloatChunk3D c = null;
		for( BufferedRandomFloat3D.FloatChunk3D f : chunks ) {
			if( f.type != type ) continue;
			if( f.level != level ) continue;
			if( f.vx != vx ) continue;
			if( f.vy != vy ) continue;
			if( f.vz != vz ) continue;
			
			c = f;
			break;
		}
		
		if( c != null )
			chunks.remove( c );
		else
			c = new BufferedRandomFloat3D.FloatChunk3D( vx, vy, vz, level, type );
		
		chunks.addFirst( c );
		
		while( chunks.size() > MAX_LOADED_CHUNKS )
			chunks.removeLast();
		
		return c.raster.getValue( dx, dy, dz );
	}
	
	private class FloatChunk3D {
		private final int vx, vy, vz, level, type;
		private PlainRasterFloat3D raster = new PlainRasterFloat3D( CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE );
		
		public FloatChunk3D( int vx, int vy, int vz, int level, int type ) {
			this.vx = vx;
			this.vy = vy;
			this.vz = vz;
			this.level = level;
			this.type = type;
	
			load();
		}

		private String getFileName() {
			return bufferRoot + "/rf_" + vx + "_" + vy + "_" + vz + "_" + level + "_" + type + ".chunk";
		}
		
		private void load() {
			File f = new File( getFileName() );
			f.deleteOnExit();
			
			if( f.exists() ) {
				MIn in = new MIn( getFileName() );
				System.arraycopy( in.readFloat( CHUNK_SIZE*CHUNK_SIZE*CHUNK_SIZE ), 0, raster.data, 0, CHUNK_SIZE*CHUNK_SIZE*CHUNK_SIZE );
				in.close();
				//System.out.println( "3D Load (" + vx + "/" + vy + "/" + vz + " s:" + level + " type:" + type );
			} else {
				for( int i = 0; i < raster.data.length; i++ )
					raster.data[i] = rnd.nextFloat();
				MOut out = new MOut( getFileName(), true );
				out.writeFloat( raster.data );
				out.close();
				//System.out.println( "3D Save (" + vx + "/" + vy + "/" + vz + " s:" + level + " type:" + type );
			}
		}

	}
	
}
